# -*- coding: utf-8 -*-
#                    _
#     /\            | |
#    /  \   _ __ ___| |__   ___ _ __ _   _
#   / /\ \ | '__/ __| '_ \ / _ \ '__| | | |
#  / ____ \| | | (__| | | |  __/ |  | |_| |
# /_/    \_\_|  \___|_| |_|\___|_|   \__, |
#                                     __/ |
#                                    |___/
# Copyright (C) 2017 Anand Tiwari
#
# Email:   anandtiwarics@gmail.com
# Twitter: @anandtiwarics
#
# This file is part of ArcherySec Project.

""" Author: Anand Tiwari """

from __future__ import unicode_literals

import uuid
from datetime import datetime

from django.contrib import messages
from django.core.files.storage import FileSystemStorage
from django.shortcuts import HttpResponseRedirect, render
from django.urls import reverse
from rest_framework import status
from rest_framework.permissions import IsAuthenticated
from rest_framework.renderers import TemplateHTMLRenderer
from rest_framework.response import Response
from rest_framework.views import APIView

from pentest.models import (PentestScanDb, PentestScanResultsDb,
                            VulnerabilityData)
from pentest.serializers import PentestCreateSerializers, PentestSerializers
from projects.models import ProjectDb
from user_management import permissions

from .forms import *


class PentestList(APIView):
    renderer_classes = [TemplateHTMLRenderer]
    template_name = "pentest/list_scan.html"

    permission_classes = (IsAuthenticated,)

    def get(self, request):
        pentest = PentestScanDb.objects.all()
        serialized_data = PentestSerializers(pentest)
        return Response({"serializer": serialized_data, "pentest": pentest})


class PentestCreate(APIView):
    renderer_classes = [TemplateHTMLRenderer]
    template_name = "pentest/add_list_scan.html"

    permission_classes = (
        IsAuthenticated,
        permissions.IsAnalyst,
    )

    def get(self, request):
        project = ProjectDb.objects.all()
        return Response({"all_projects": project})

    def post(self, request):
        scan_url = request.POST.get("scan_url")
        project_id = request.POST.get("project_id")
        pentest_type = request.POST.get("pentest_type")
        scanid = uuid.uuid4()

        project_uu_id = ProjectDb.objects.filter(uu_id=project_id).get().id

        dump_scan = PentestScanDb(
            scan_url=scan_url,
            scan_id=scanid,
            pentest_type=pentest_type,
            project_id=project_uu_id,
        )
        dump_scan.save()

        messages.success(request, "Pentest Project Created")

        return HttpResponseRedirect("/pentest/")


class PentestDelete(APIView):
    renderer_classes = [TemplateHTMLRenderer]
    template_name = "pentest/list_scan.html"

    permission_classes = (
        IsAuthenticated,
        permissions.IsAnalyst,
    )

    def post(self, request):
        get_scan_id = request.POST.get("scan_id")

        scan_item = str(get_scan_id)
        value = scan_item.replace(" ", "")
        value_split = value.split(",")
        split_length = value_split.__len__()
        for i in range(0, split_length):
            scan_id = value_split.__getitem__(i)

            del_scan = PentestScanResultsDb.objects.filter(scan_id=scan_id)
            del_scan.delete()

            del_scan_info = PentestScanDb.objects.filter(scan_id=scan_id)
            del_scan_info.delete()

        return HttpResponseRedirect("/pentest/")


class PentestListVuln(APIView):
    renderer_classes = [TemplateHTMLRenderer]
    template_name = "pentest/manual_vuln_list.html"

    permission_classes = (IsAuthenticated,)

    def get(self, request):
        scan_id = request.GET["scan_id"]
        project_id = request.GET["project_id"]

        if scan_id == None:
            messages.error(request, "ID Invalid")
            return HttpResponseRedirect("/pentest/")
        else:
            try:
                all_vuln = PentestScanResultsDb.objects.filter(scan_id=scan_id)
            except PentestScanResultsDb.DoesNotExist:
                return Response({"scan_id": scan_id})
        return Response(
            {"all_vuln": all_vuln, "scan_id": scan_id, "project_id": project_id}
        )


class PentestVulnCreate(APIView):
    renderer_classes = [TemplateHTMLRenderer]
    template_name = "pentest/add_manual_vuln.html"

    permission_classes = (IsAuthenticated, permissions.IsAnalyst)

    def get(self, request):
        scan_id = request.GET["scan_id"]
        project_id = request.GET["project_id"]

        if scan_id == None:
            messages.error(request, "ID Invalid")
            return HttpResponseRedirect("/pentest/")
        else:
            try:
                all_vuln = PentestScanResultsDb.objects.get(scan_id=scan_id)
                serialized_data = PentestCreateSerializers(all_vuln, many=False)
            except PentestScanResultsDb.DoesNotExist:
                return Response(
                    {"message": "Id Doesn't Exist"}, status=status.HTTP_404_NOT_FOUND
                )
        return Response(
            {
                "serializer": serialized_data,
                "all_vuln": all_vuln,
                "project_id": project_id,
            }
        )

    def post(self, request):

        severity_color = ""
        uploaded_poc_url = ""

        vuln_name = request.POST.get("vuln_name")
        severity = request.POST.get("vuln_severity")
        vuln_url = request.POST.get("vuln_instance")
        description = request.POST.get("vuln_description")
        solution = request.POST.get("vuln_solution")
        reference = request.POST.get("vuln_reference")
        scan_id = request.POST.get("scan_id")
        project_uu_id = request.POST.get("project_id")
        project_id = (
            ProjectDb.objects.filter(uu_id=project_uu_id).values("id").get()["id"]
        )
        pentest_type = request.POST.get("pentest_type")
        poc = request.FILES.get("poc", False)
        poc_description = request.POST.get("poc_description")
        date_time = datetime.now()
        vuln_id = uuid.uuid4()

        fs = FileSystemStorage()
        if poc is not False:
            filename = fs.save(poc.name, poc)
            uploaded_poc_url = fs.url(filename)

        if severity == "High":
            severity_color = "danger"

        elif severity == "Medium":
            severity_color = "warning"

        elif severity == "Low":
            severity_color = "info"

        dump_data = PentestScanResultsDb(
            vuln_id=vuln_id,
            vuln_name=vuln_name,
            severity_color=severity_color,
            severity=severity,
            vuln_url=vuln_url,
            description=description,
            solution=solution,
            reference=reference,
            scan_id=scan_id,
            pentest_type=pentest_type,
            vuln_status="Open",
            project_id=project_id,
            Poc_Img=uploaded_poc_url,
            poc_description=poc_description,
        )
        dump_data.save()

        all_scan_data = PentestScanResultsDb.objects.filter(scan_id=scan_id)

        total_vuln = len(all_scan_data)
        total_high = len(all_scan_data.filter(severity="High"))
        total_medium = len(all_scan_data.filter(severity="Medium"))
        total_low = len(all_scan_data.filter(severity="Low"))

        PentestScanDb.objects.filter(scan_id=scan_id).update(
            date_time=date_time,
            total_vul=total_vuln,
            high_vul=total_high,
            medium_vul=total_medium,
            low_vul=total_low,
        )

        messages.success(request, "Pentest Vulnerability Created")

        return HttpResponseRedirect(reverse("pentest:list_scan"))


class NewVulnCreate(APIView):
    renderer_classes = [TemplateHTMLRenderer]
    template_name = "pentest/add_vulnerability.html"

    permission_classes = (IsAuthenticated, permissions.IsAnalyst)

    def get(self, request):
        all_vuln_data = VulnerabilityData.objects.all()
        scan_id = request.GET["scan_id"]
        vuln_id = request.GET["vuln_id"]
        project_id = request.GET["project_id"]

        all_vuln = PentestScanResultsDb.objects.filter(scan_id=scan_id)
        vuln_data = VulnerabilityData.objects.filter(vuln_data_id=vuln_id)
        return render(
            request,
            "pentest/add_vulnerability.html",
            {
                "all_vuln": all_vuln,
                "vuln_data": vuln_data,
                "all_vuln_data": all_vuln_data,
                "scan_id": scan_id,
                "project_id": project_id,
            },
        )


class GetPentestVuln(APIView):
    renderer_classes = [TemplateHTMLRenderer]
    template_name = "pentest/manual_vuln_data.html"

    permission_classes = (IsAuthenticated,)

    def get(self, request):
        vuln_id = request.GET["vuln_id"]

        vuln_detail = PentestScanResultsDb.objects.filter(vuln_id=vuln_id)
        return render(
            request, "pentest/manual_vuln_data.html", {"vuln_detail": vuln_detail}
        )


class EditPentestVuln(APIView):
    renderer_classes = [TemplateHTMLRenderer]
    template_name = "pentest/edit_vuln.html"

    permission_classes = (IsAuthenticated, permissions.IsAnalyst)

    def get(self, request):
        vuln_id = request.GET["vuln_id"]

        if vuln_id == None:
            messages.error(request, "ID Invalid")
            return HttpResponseRedirect("/pentest/")
        else:
            try:
                vuln_data = PentestScanResultsDb.objects.filter(vuln_id=vuln_id)
            except PentestScanResultsDb.DoesNotExist:
                return Response(
                    {"message": "Id Doesn't Exist"}, status=status.HTTP_404_NOT_FOUND
                )
        return Response({"vuln_data": vuln_data, "vuln_id": vuln_id})

    def post(self, request):
        vuln_id = request.GET["vuln_id"]

        severity_color = None
        vuln_id = request.POST.get("vuln_id")
        project_id = request.POST.get("project_id")
        vuln_name = request.POST.get("vuln_name")
        severity = request.POST.get("vuln_severity")
        vuln_url = request.POST.get("vuln_instance")
        description = request.POST.get("vuln_description")
        solution = request.POST.get("vuln_solution")
        reference = request.POST.get("vuln_reference")
        scan_id = request.POST.get("scan_id")
        date_time = datetime.now()

        if severity == "High":
            severity_color = "danger"

        elif severity == "Medium":
            severity_color = "warning"

        elif severity == "Low":
            severity_color = "info"

        PentestScanResultsDb.objects.filter(vuln_id=vuln_id).update(
            vuln_name=vuln_name,
            severity=severity,
            vuln_url=vuln_url,
            description=description,
            solution=solution,
            reference=reference,
            severity_color=severity_color,
        )
        all_scan_data = PentestScanResultsDb.objects.filter(scan_id=scan_id)

        total_vuln = len(all_scan_data)
        total_high = len(all_scan_data.filter(severity="High"))
        total_medium = len(all_scan_data.filter(severity="Medium"))
        total_low = len(all_scan_data.filter(severity="Low"))

        PentestScanDb.objects.filter(scan_id=scan_id).update(
            date_time=date_time,
            total_vul=total_vuln,
            high_vul=total_high,
            medium_vul=total_medium,
            low_vul=total_low,
        )

        messages.success(request, "Pentest Vulnerability Edited")

        return HttpResponseRedirect(
            reverse("pentest:vuln_list")
            + "?scan_id=%s&project_id=%s" % (scan_id, project_id),
            {"scan_id": scan_id},
        )


class PentestVulnData(APIView):
    renderer_classes = [TemplateHTMLRenderer]
    template_name = "pentest/manual_vuln_data.html"

    permission_classes = (IsAuthenticated, permissions.IsAnalyst)

    def post(self, request):
        vuln_id = request.POST.get("vuln_id")
        status = request.POST.get("status")
        scan_id = request.POST.get("scan_id")
        project_id = request.POST.get("project_id")
        date_time = datetime.now()

        PentestScanResultsDb.objects.filter(vuln_id=vuln_id).update(
            vuln_status=status,
            date_time=date_time,
        )
        all_scan_data = PentestScanResultsDb.objects.filter(
            scan_id=scan_id, vuln_status="Open"
        )

        total_vuln = len(all_scan_data)
        total_high = len(all_scan_data.filter(severity="High"))
        total_medium = len(all_scan_data.filter(severity="Medium"))
        total_low = len(all_scan_data.filter(severity="Low"))

        PentestScanDb.objects.filter(scan_id=scan_id).update(
            date_time=date_time,
            total_vul=total_vuln,
            high_vul=total_high,
            medium_vul=total_medium,
            low_vul=total_low,
        )
        messages.success(request, "Marked as %s" % status)
        return HttpResponseRedirect(
            reverse("pentest:vuln_list")
            + "?scan_id=%s&project_id=%s" % (scan_id, project_id),
            {"scan_id": scan_id},
        )


class PentestVulnDelete(APIView):
    renderer_classes = [TemplateHTMLRenderer]
    template_name = "pentest/manual_vuln_list.html"

    permission_classes = (IsAuthenticated, permissions.IsAnalyst)

    def post(self, request):
        scan_id = request.POST.get("scan_id")
        get_vuln_id = request.POST.get("vuln_id")
        project_id = request.POST.get("project_id")

        scan_item = str(get_vuln_id)
        value = scan_item.replace(" ", "")
        value_split = value.split(",")
        split_length = value_split.__len__()
        for i in range(0, split_length):
            vuln_id = value_split.__getitem__(i)
            del_vuln = PentestScanResultsDb.objects.filter(vuln_id=vuln_id)
            del_vuln.delete()

        all_scan_data = PentestScanResultsDb.objects.filter(scan_id=scan_id)

        total_vuln = len(all_scan_data)
        total_high = len(all_scan_data.filter(severity="High"))
        total_medium = len(all_scan_data.filter(severity="Medium"))
        total_low = len(all_scan_data.filter(severity="Low"))

        PentestScanDb.objects.filter(scan_id=scan_id).update(
            total_vul=total_vuln,
            high_vul=total_high,
            medium_vul=total_medium,
            low_vul=total_low,
        )

        messages.success(request, "Vulnerability Deleted")

        return HttpResponseRedirect(
            reverse("pentest:vuln_list")
            + "?scan_id=%s&project_id=%s" % (scan_id, project_id),
            {"scan_id": scan_id},
        )


class AddVulnData(APIView):
    renderer_classes = [TemplateHTMLRenderer]
    template_name = "pentest/manual_vuln_data.html"

    permission_classes = (IsAuthenticated, permissions.IsAnalyst)

    def post(self, request):
        vuln_data_id = uuid.uuid4()
        vuln_name = request.POST.get("vuln_name")
        vuln_description = request.POST.get("vuln_description")
        vuln_severity = request.POST.get("vuln_severity")
        vuln_remediation = request.POST.get("vuln_remediation")
        vuln_references = request.POST.get("vuln_references")

        dump_data = VulnerabilityData(
            vuln_data_id=vuln_data_id,
            vuln_name=vuln_name,
            vuln_description=vuln_description,
            vuln_severity=vuln_severity,
            vuln_remediation=vuln_remediation,
            vuln_references=vuln_references,
        )
        dump_data.save()

        return HttpResponseRedirect(reverse("pentest:list_scan"))
